//
// Created by zhouwd on 2019/7/23.
//

#include "media_video_decode.h"

void _MEDIA_VIDEO_DECODE::run() {

    bool isMediaEOS = false;
    this->mediaVideoFrame->prepare();
    FILE *pFile = fopen ("/sdcard/zhouwd/11111.h264", "wb");
    while (!isMediaEOS) {
        ssize_t inputBufferIndex = AMediaCodec_dequeueInputBuffer(videoCodec,1000);
        //ALOGE("_MEDIA_VIDEO_DECODE > run > inputBufferIndex > %d", inputBufferIndex);
        if (inputBufferIndex >= 0) {
            // 获取buffer的索引
            size_t out_size;

            uint8_t *inputBuf = AMediaCodec_getInputBuffer(videoCodec, inputBufferIndex, &out_size);

            ssize_t sampleSize = AMediaExtractor_readSampleData(extractor, inputBuf, out_size);
            ALOGE("_MEDIA_VIDEO_DECODE > run > sampleSize > %d", sampleSize);
            fwrite (inputBuf , 1, sampleSize, pFile);
            if (sampleSize < 0 ) {
                sampleSize = 0;
                //AMediaCodec_queueInputBuffer(videoCodec, inputBufferIndex, 0, 0, 0, AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM);
                isMediaEOS = true;
                //mediaVideoData->setStop();
            }

            int64_t presentationTimeUs = AMediaExtractor_getSampleTime(extractor);
            ALOGE("_MEDIA_VIDEO_DECODE > run > presentationTimeUs > %lld", presentationTimeUs);
            usleep(presentationTimeUs / 1000);
            media_status_t status = AMediaCodec_queueInputBuffer(videoCodec, inputBufferIndex, 0, sampleSize, presentationTimeUs,isMediaEOS ? AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM : 0);
            AMediaExtractor_advance(extractor);

        }

        AMediaCodecBufferInfo info;

        int status = AMediaCodec_dequeueOutputBuffer(videoCodec, &info, 1000);

        //ALOGE("dequeueOutputBuffer returned: %d", status);

        if (status >= 0) {
            if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
                isMediaEOS = true;
            }
            size_t outsize;
            uint8_t *outputBuf = AMediaCodec_getOutputBuffer(videoCodec, status, &outsize);

            ALOGE("dequeueOutputBuffer > run > outputBuf > outsize > %d > size > %d > offset > %d" , outsize, info.size, info.offset);
            if (outputBuf != nullptr) {

                int num;
                AMediaFormat *format = AMediaCodec_getOutputFormat(videoCodec);
                AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, &num) ;

                int width;
                AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width) ;
                int height;
                AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height) ;
                ALOGE("dequeueOutputBuffer > run > outputBuf > num > %d > width > %d > height > %d" , num, width, height);

                this->mediaVideoFrame->updateVideoFrameData(outputBuf, width, height);
            }
            AMediaCodec_releaseOutputBuffer(videoCodec, status, true);



            //ALOGE("dequeueOutputBuffer returned: > 0");
        } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
            //ALOGE("dequeueOutputBuffer returned: AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED");
        } else if(status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
            //ALOGE("dequeueOutputBuffer returned: AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED");
        } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
            //ALOGE("dequeueOutputBuffer returned: AMEDIACODEC_INFO_TRY_AGAIN_LATER");
        } else {
            //ALOGE("dequeueOutputBuffer returned: else");
        }
    }
}

int _MEDIA_VIDEO_DECODE::startDecode() {

    start();

    return 0;
}

int _MEDIA_VIDEO_DECODE::init(const char *filename) {
    ALOGE("_MEDIA_VIDEO_DECODE > init > filename > %s", filename);
    extractor = AMediaExtractor_new();

    media_status_t mediaVideoDataSource = AMediaExtractor_setDataSource(extractor, filename);
    ALOGE("_MEDIA_VIDEO_DECODE > init > mediaVideoDataSource > %d", mediaVideoDataSource);
    if (mediaVideoDataSource != AMEDIA_OK) {
        return -1;
    }

    size_t videoTrackCount = AMediaExtractor_getTrackCount(extractor);

    if (videoTrackCount <= 0) {
        return -2;
    }

    for (size_t i = 0; i < videoTrackCount; ++i) {

        AMediaFormat *format = AMediaExtractor_getTrackFormat(extractor, i);

        const char* s;

        AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &s);

        ALOGE("MediaExtractor > init > %s", s);

        if (strncmp(s, "video/" , 6) == 0) {

            media_status_t trackStatus = AMediaExtractor_selectTrack(extractor, i);
            ALOGE("MediaExtractor > trackStatus > video > %d > i > %d", trackStatus, i);

            int32_t frameRate;

            AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, &frameRate);

            ALOGE("MediaExtractor > video > frameRate > %d", frameRate);

            AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &width);
            ALOGE("MediaExtractor > video > width > %d", width);

            int32_t realWidth;
            AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_STRIDE, &realWidth);
            ALOGE("MediaExtractor > video > realWidth > %d", realWidth);

            AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &height);
            ALOGE("MediaExtractor > video > height > %d", height);



            videoCodec = AMediaCodec_createDecoderByType(s);
            AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, 21);
            media_status_t videoRc = AMediaCodec_configure(videoCodec, format, NULL, NULL, 0);

            ALOGE("MediaExtractor > video > videoRc > %d", videoRc);
            media_status_t startRc = AMediaCodec_start(videoCodec);
            ALOGE("MediaExtractor > video > startRc > %d", startRc);
        }
    }

    return 0;
}

_MEDIA_VIDEO_DECODE::_MEDIA_VIDEO_DECODE() {

}

_MEDIA_VIDEO_DECODE::~_MEDIA_VIDEO_DECODE() {

}

int32_t _MEDIA_VIDEO_DECODE::getWidth() {


    return width;
}

int32_t _MEDIA_VIDEO_DECODE::getHeight() {


    return height;
}

int _MEDIA_VIDEO_DECODE::initMediaVideoFrame(MediaVideoFrame *mediaVideoFrame) {
    this->mediaVideoFrame = mediaVideoFrame;
    return 0;
}
